package com.shujia.mllib

import org.apache.spark.ml.classification.{LogisticRegression, LogisticRegressionModel}
import org.apache.spark.sql.{DataFrame, Dataset, Row, SparkSession}

object Demo2Person {
  def main(args: Array[String]): Unit = {

    /**
     * 1、对数据进行特征工程处理
     * 将数据变成机器学习中的模型能够接收的数据
     */

    val spark: SparkSession = SparkSession
      .builder()
      .master("local[*]")
      .appName("Demo2Person")
      .getOrCreate()

    val personDF: DataFrame = spark
      .read
      .format("libsvm")
      .load("spark/data/人体指标.txt")

    personDF.printSchema()
    personDF.show()

    /**
     * 2、将数据切分为训练集和测试集，一般比例为7:3
     */

    val splitArr: Array[Dataset[Row]] = personDF.randomSplit(Array(0.7, 0.3))
    val trainData: Dataset[Row] = splitArr(0) // 训练集
    val testData: Dataset[Row] = splitArr(1) // 测试集

    /**
     * 3、选择合适的算法（模型） 进行训练
     * 看数据中有没有label:
     * 有 -> 监督学习 --> 看label是连续的还是离散的
     * --> 连续的 => 回归
     * --> 离散的 => 分类
     * 无 -> 无监督学习
     *
     * 逻辑回归
     */

    val lr: LogisticRegression = new LogisticRegression()
      .setMaxIter(10) // 设置最大迭代次数
      .setFitIntercept(true) // 有没有截距

    /**
     * 4、将训练集带入模型进行训练
     */

    val model: LogisticRegressionModel = lr.fit(trainData)

    /**
     * 5、使用测试集评估模型
     * 评估模型标准：
     * 准确率、精确率、召回率、F1 score
     */

    val resDF: DataFrame = model.transform(testData)
    resDF.show(1000, false)

    import spark.implicits._
    import org.apache.spark.sql.functions._

    // 将数据中原有的label 同 预测出来的结果 prediction 进行比较 计算模型的准确率

    resDF
      .select(sum(when($"label" === $"prediction", 1).otherwise(0)) / count($"label"))
      .show()

    /**
     * 6、模型评估后符合要求，将模型进行保存，以便下一次应用
     * 一般要求准确率达到95%
     */
    model.save("spark/data/personModel")

  }

}
